﻿#region File Header
//-----------------------------------------------------------------------------
// SibLib
//
// Copyright (C) 2010 Julien Villers
// This program is distributed under the terms of the 
// GNU Lesser General Public License (LGPL).
// See Docs/lgpl.txt and Docs/gpl.txt
//-----------------------------------------------------------------------------
#endregion

using System.Collections.Generic;

namespace SibLib.Containers
{
    // TODO: consider inheritance from List<T>.
    public class AutoList<T>
    {
        #region Members
        private List<T> m_ListToAdd;
        private List<T> m_List;
        private List<T> m_ListToRemove;
        #endregion

        #region Properties
        public T this[int index]
        {
            get { return m_List[index]; }
            set { m_List[index] = value; }
        }

        public int Count
        {
            get { return m_List.Count; }
        }

        public int Capacity
        {
            get { return m_List.Capacity; }
            set { m_List.Capacity = value; m_ListToAdd.Capacity = value / 2; m_ListToRemove.Capacity = value / 2; }
        }
        #endregion

        #region Events
        public delegate void NotifyItemAdded(T item);
        public delegate void NotifyItemRemoved(T item);
        public delegate void NotifyItemModified(T item, int info);
        public event NotifyItemAdded ItemAdded;
        public event NotifyItemRemoved ItemRemoved;
        public event NotifyItemModified ItemModified;       // Fired manually by OnItemModified(item);
        #endregion

        #region Constructors
        public AutoList()
        {
            m_List = new List<T>();
            m_ListToAdd = new List<T>();
            m_ListToRemove = new List<T>();
        }

        public AutoList(int capacity)
        {
            m_List = new List<T>(capacity);
            m_ListToAdd = new List<T>(capacity / 2);
            m_ListToRemove = new List<T>(capacity / 2);
        }
        #endregion

        #region Public API - Content
        public void Add(T item)
        {
            m_ListToAdd.Add(item);
        }

        public void Remove(T item)
        {
            m_ListToRemove.Add(item);
        }

        public void RemoveAt(int index)
        {
            m_ListToRemove.Add(m_List[index]);
        }

        public void Clear()
        {
            m_ListToAdd.Clear();
            m_ListToRemove.AddRange(m_List);
        }
        #endregion

        #region Public API - Update
        public void ProcessAdds()
        {
            foreach (T item in m_ListToAdd)
            {
                m_List.Add(item);
                if (ItemAdded != null)
                    ItemAdded(item);
            }
            m_ListToAdd.Clear();
        }

        public void ProcessRemoves()
        {
            foreach (T item in m_ListToRemove)
            {
                m_List.Remove(item);
                if (ItemRemoved != null)
                    ItemRemoved(item);
            }
            m_ListToRemove.Clear();
        }
        #endregion

        #region Public API - List access
        /// <summary>
        /// Use with MAXIMUM caution.
        /// </summary>
        /// <returns></returns>
        public List<T> GetAddList()
        {
            return m_ListToAdd;
        }

        /// <summary>
        /// Use with MAXIMUM caution.
        /// </summary>
        /// <returns></returns>
        public List<T> GetRemoveList()
        {
            return m_ListToRemove;
        }

        /// <summary>
        /// Return an array version of the active list.
        /// </summary>
        /// <returns></returns>
        public T[] ToArray()
        {
            return m_List.ToArray();
        }

        public bool Contains(T item)
        {
            return (m_List.Contains(item) || m_ListToAdd.Contains(item));
        }

        public int IndexOf(T item)
        {
            return m_List.IndexOf(item);
        }

        #endregion

        #region Public API - Notification
        public void OnItemModified(T item, int info)
        {
            if (ItemModified != null)
                ItemModified(item, info);
        }
        #endregion

        #region Enumeration
        /// <summary>
        /// Enumerator.
        /// </summary>
        /// <returns></returns>
        public List<T>.Enumerator GetEnumerator()
        {
            return m_List.GetEnumerator();
        }

        #endregion
    }
}
